package McCabe;

import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.StringReader;

public class NroCiclomatico {
	int numeroCiclomatico;
	int cantidadDeSwitch = 0, cantidadDeDefault = 0, cantidadDeIf = 0,
			cantidadDeFor = 0, cantidadDeWhile = 0, cantidadDeCatch = 0,
			cantidadDeCase = 0, cantidadDeAnd = 0, cantidadDeOr = 0;

	// public static void main(String[] args) {
	// NroCiclomatico obj = new NroCiclomatico();
	// obj.ProcesarMetodo("d:/code.txt");
	// obj.informarNroCiclomatico();
	// // obj.informarCiclomatico();
	// // obj.informarHalstead();
	// }

	/**
	 * Funcion: calcularNumeroCiclomatico(); Retorna: Void Recibe : -- Objetivo:
	 * Sumar la cantidad de Nodos predicados para obtener el Nro Ciclomatico
	 * total del metodo
	 */
	public void calcularNumeroCiclomatico() {
		numeroCiclomatico = cantidadDeIf + cantidadDeFor + cantidadDeWhile
				+ cantidadDeAnd + cantidadDeOr + cantidadDeCatch
				+ cantidadDeCase + cantidadDeSwitch + 1;
		// numeroCiclomatico+=cantidadDeCatch;
		// numeroCiclomatico+=cantidadDeCase+cantidadDeSwitch;
		// numeroCiclomatico+=1;
	}

	/**
	 * Funcion: ProcesarMetodo(); Retorna: Void Recibe : String (Ruta del del
	 * archivo a procesar) Objetivo: Abre el archivo para su procesamiento, el
	 * archivo solo debe contener un metodo, para que el calculo sea correcto.
	 * Ya que no discrimina por funciones.
	 */
	public void ProcesarMetodo(String textoFuncion) {
		String linea;

		BufferedReader br = new BufferedReader(new StringReader(textoFuncion));
		boolean bComentarioComp = false;
		try {

			while ((linea = br.readLine()) != null) // Lee linea a linea y
													// procesa
			{
				if (linea.length() != 0) // Si la linea no es vacia
				{
					if (bComentarioComp == false) {
						linea = linea.replace(" ", ""); // Quita los espacios
						linea = QuitarComentariosComplejoInicioFinal(linea);

						if (BuscaComentariosComplejoInicio(linea)) // Encontro
																	// el inicio
																	// de un
																	// comentario
																	// complejo
						{
							bComentarioComp = true;
							linea = QuitarComentariosComplejoInicio(linea);
							linea = QuitarComentariosSimples(linea);
							linea = QuitarTextoEntreComillas(linea);
							System.out.println("Linea: " + linea);
						}
					} else {
						if (BuscaComentariosComplejoFinal(linea)) // Encontro
																	// fin de
																	// comentario
																	// complejo
						{
							bComentarioComp = false;
							linea = QuitarComentariosComplejoFinal(linea);
							linea = QuitarComentariosSimples(linea);
							linea = QuitarTextoEntreComillas(linea);
						} else
							linea = "";
					}
					linea = QuitarComentariosSimples(linea);
					linea = QuitarTextoEntreComillas(linea);
					contarNodosPredicados(linea);
				}
			}
			calcularNumeroCiclomatico(); // Terminado el ciclo suma los Nodos
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

	/**
	 * Funcion: QuitarTextoEntreComillas(); Retorna: String Recibe : String
	 * Objetivo: Busca 2 caracteres comillas y quita lo que hay en medio de las
	 * mismas
	 */

	public String QuitarTextoEntreComillas(String linea) {
		int primerCar;
		String aux = linea;
		primerCar = linea.indexOf("\"", 0); // Busca el primer caracter COMILLAS
		if (primerCar >= 0) // Si encontro unas comillas
		{
			int segundoCar = linea.indexOf("\"", primerCar + 1); // Busca el
																	// segundo
																	// caracter
																	// COMILLAS
																	// desde la
																	// siguiente
																	// pos a la
																	// primer
																	// encontrada
			if (primerCar >= 0 && segundoCar >= 0) // Si ambas busquedas
													// tuvieron exito
			{
				aux = linea.substring(0, primerCar)
						+ linea.substring(segundoCar + 1, linea.length());
				aux = aux.trim();
			}
		}
		return aux;
	}

	/**
	 * Funcion: QuitarComentariosSimples(); Retorna: String Recibe : String
	 * Objetivo: Busca Comentarios de linea para eliminarlos
	 */

	public String QuitarComentariosSimples(String linea) {
		int primerCar;
		String aux = linea;
		primerCar = linea.indexOf("//", 0); // Busca la cadena // para eliminar
											// desde alli al final
		if (primerCar >= 0) // Si encontro
		{
			aux = linea.substring(0, primerCar);
			aux = aux.trim();
		}
		return aux;
	}

	/**
	 * Funcion: QuitarComentariosComplejoInicioFinal(); Retorna: String Recibe :
	 * String Objetivo: Busca comentarios complejos para retornar la linea
	 */

	public String QuitarComentariosComplejoInicioFinal(String linea) {
		int primerCar;
		String aux = linea;
		primerCar = linea.indexOf("/*", 0); // Busca el primer caracter
		if (primerCar >= 0) // Si encontro unas comillas
		{
			int segundoCar = linea.indexOf("*/", primerCar + 2); // Busca el
																	// segundo
																	// caracter
																	// desde la
																	// siguiente
																	// pos a la
																	// primer
																	// encontrada
			if (primerCar >= 0 && segundoCar >= 0) // Si ambas busquedas
													// tuvieron exito
			{
				aux = linea.substring(0, primerCar)
						+ linea.substring(segundoCar + 2, linea.length());
				aux = aux.trim();
			}
		}
		return aux;
	}

	/**
	 * Funcion: QuitarComentariosComplejoInicio(); Retorna: String Recibe :
	 * String Objetivo: Busca comentarios complejos para retornar la linea
	 */

	public String QuitarComentariosComplejoInicio(String linea) {
		int primerCar;
		String aux = linea;
		primerCar = linea.indexOf("/*", 0); // Busca el primer caracter
		if (primerCar >= 0) // Si encontro el caracter
		{
			aux = linea.substring(0, primerCar);
			aux = aux.trim();
		}
		return aux;
	}

	/**
	 * Funcion: BuscaComentariosComplejoInicio(); Retorna: Bool Recibe : String
	 * Objetivo: Busca Inicio de comentarios complejos para retornar ture o
	 * false
	 */

	public boolean BuscaComentariosComplejoInicio(String linea) {
		int primerCar;
		String aux = linea;
		primerCar = linea.indexOf("/*", 0); // Busca el primer caracter
		if (primerCar >= 0) // Si encontro unas comillas
		{
			return true;
		}
		return false;
	}

	/**
	 * Funcion: BuscaComentariosComplejoFinal(); Retorna: Bool Recibe : String
	 * Objetivo: Busca Inicio de comentarios complejos para retornar true o
	 * false
	 */

	public boolean BuscaComentariosComplejoFinal(String linea) {
		int primerCar;
		String aux = linea;
		primerCar = linea.indexOf("*/", 0); // Busca el ultimo caracter
		if (primerCar >= 0) // Si encontro unas comillas
		{
			return true;
		}
		return false;
	}

	/**
	 * Funcion: QuitarComentariosComplejoFinal(); Retorna: String Recibe :
	 * String Objetivo: Busca comentarios complejos para retornar la linea
	 */

	public String QuitarComentariosComplejoFinal(String linea) {
		int primerCar;
		String aux = linea;
		primerCar = linea.indexOf("*/", 0); // Busca el primer caracter /*
		if (primerCar >= 0) // Si encontro unas comillas
		{
			aux = linea.substring(primerCar + 2, linea.length());
			aux = aux.trim();
		}
		return aux;
	}

	/**
	 * Funcion: ContarOcurrenciaDePalabras(); Retorna: Int Recibe : String,
	 * String Objetivo: Busca la cantidad de veces que una palabra aparece en
	 * una linea
	 */

	public int ContarOcurrenciaDePalabras(String linea, String patron) {

		int count = 0, start = 0, len = patron.length();
		// while((start = linea.indexOf(patron, start+=len)) > -1)
		// count++;

		while ((start = linea.indexOf(patron, start) + 1) > 0) {
			count++;
		}

		return count;
	}

	/**
	 * Funcion: ContarNodosPredicados(); Retorna: -- Recibe : String Objetivo:
	 * Cuenta la cantidad de nodos predicados
	 */

	public void contarNodosPredicados(String linea) {
		// int numero;
		// cantidadDeSwitch+=ContarOcurrenciaDePalabras(linea,"switch(");
		cantidadDeDefault += ContarOcurrenciaDePalabras(linea, "default:");
		cantidadDeIf += ContarOcurrenciaDePalabras(linea, "if(");
		cantidadDeFor += ContarOcurrenciaDePalabras(linea, "for(");
		cantidadDeWhile += ContarOcurrenciaDePalabras(linea, "while(");
		cantidadDeCatch += ContarOcurrenciaDePalabras(linea, "catch(");
		cantidadDeCase += ContarOcurrenciaDePalabras(linea, "case");

		cantidadDeAnd += ContarOcurrenciaDePalabras(linea, "&&");
		cantidadDeOr += ContarOcurrenciaDePalabras(linea, "||");

		/*
		 * numero=cantidadDeIf+cantidadDeFor+cantidadDeWhile+
		 * cantidadDeAnd+cantidadDeOr+cantidadDeCatch+cantidadDeCase+
		 * cantidadDeSwitch; System.out.println("numero: " + numero + " " +
		 * "Linea: " + linea);
		 */

	}

	/**
	 * Funcion: ContarNodosPredicados(); Retorna: -- Recibe : String Objetivo:
	 * Cuenta la cantidad de nodos predicados
	 */
	public Integer informarNroCiclomatico() {
		// System.out.println("Número Ciclomático: " + numeroCiclomatico);
		// System.out.println("Cantidad de if: " + cantidadDeIf);
		// System.out.println("Cantidad de OR: " + cantidadDeOr);
		// System.out.println("Cantidad de AND: " + cantidadDeAnd);
		// System.out.println("Cantidad de for: " + cantidadDeFor);
		// System.out.println("Cantidad de while: " + cantidadDeWhile);
		// System.out.println("Cantidad de case: " + cantidadDeCase);
		// System.out.println("Cantidad de catch: " + cantidadDeCatch);
		// System.out.println("Cantidad de switch: " + cantidadDeSwitch);

		return numeroCiclomatico;
	}

	/**
	 * Funcion: Informa los nodos condicion y la cantidad de apariciones
	 */
	public String informarNodosCondicion() {

		String str = new String();

		if (cantidadDeIf > 0) {
			str = str.concat("IF:" + cantidadDeIf + ", ");
		}
		if (cantidadDeOr > 0) {
			str = str.concat("OR:" + cantidadDeOr + ", ");
		}
		if (cantidadDeAnd > 0) {
			str = str.concat("AND:" + cantidadDeAnd + ", ");
		}
		if (cantidadDeFor > 0) {
			str = str.concat("FOR:" + cantidadDeFor + ", ");
		}
		if (cantidadDeWhile > 0) {
			str = str.concat("WHILE:" + cantidadDeWhile + ", ");
		}
		if (cantidadDeCase > 0) {
			str = str.concat("CASE:" + cantidadDeCase + ", ");
		}
		if (cantidadDeCatch > 0) {
			str = str.concat("CATCH:" + cantidadDeCatch + ", ");
		}
		if (cantidadDeDefault > 0) {
			str = str.concat("DEFAULT:" + cantidadDeDefault + ", ");
		}
		
		return str;
	}
}
